limit不能作为子查询,但是可以作为临时表

1. limit 分页

  • 该表的所有数据


  • 获取前4条数据 

select * from t1 limit 4;  


  • 从第2行开始(不包括2),获取4条数据

select * from t1 limit 2,4;


  • 获取4条数据,从第2行开始(不包括2)-> 和上面的功能是一样的只是写法不一样

select * from t1 limit 4 offset 2; 


2. limit 分页性能的优化 -> 记录当前页最大或最小的id -> 一般搭配着后台语言(Python,PHP)实现

  • 这里所使用到的 userinfo 表是索引章节中的表

  • 不建议使用 between 去做分页的优化,因为 id 有可能不是连续的(1,2,3,5,6,7,8,9,10,11),例如每一页有10数据,我要取第一页的数据此时 id 为 4 的这条数据被删除了,在不知情的情况下我们使用 between 1 and 10 获取数据那么只会获取到9条数据,而不是10条,如果真的要使用 between 去做分页优化的前提是 id 是连续不间断的

  • 如果直接使用 limit 在不做任何优化的情况下,页数越大速度越慢

# 比如现在有一百万条数据,每一页有10条数据,现在要取第100页的数据, MySQL会将前面的1000条数据查找(扫描)一遍找到第1000条数据,然后再从第1000条数据开始往后取10条数据

select * from userinfo limit 10000,10;

  • 上一页和下一页功能的分页优化

# 下一页的SQL语句 -> 记录当前页最后一条数据的id,然后查找大于该id的所有数据,然后再通过limit取该堆数据中的前10条数据 -> 因为MySQL是直接从该页的最后一条数据的开始查找数据,这样就不会像直接使用limit一样,需要从头开始扫描到指定的数据然后在进行获取该数据的后 num 位数据

# 比如该页最后一条数据的id是999990,然后查找id大于999990的数据,然后再通过limit取该堆数据中的前10条数据

select * from userinfo where id>999990 limit 10;



# 上一页的SQL语句 -> 记录当前页的第一条数据的id,然后查找小于该id的所有数据,然后进行倒序排序再通过limit取该堆数据中的前10条数据

# 比如该页第一条数据的id是999991,然后查找id小于999991的数据,然后进行倒序排序再通过limit取该堆数据中的前10条数据

select * from (select * from userinfo where id<999991 order by id desc limit 10) as A order by id asc;



  • 基于当前的页数往后跳几页的分页优化

    • 上一页 98 99 [100] 101 102 103 下一页

# 思路

# 计算所要跳转的页数和当前页数相差多少条数据,获取这堆相差的数据,然后进行倒序排序后使用limit获取这堆相差数据的前10条数据(前提是每一页数据为10条),而这前10条数据就是所要跳转页数的数据,最后对这10条数据进行正序排序

# 例如:当前页数是100,然后要获取103页数的数据,前提每一页数据为10条,因为103页数和当前页数相差30数据,所以首先要获取这相差的30条数据,然后再对这30条数据进行倒序排序后使用 limit 获取前10条,而这前10条就是103页数的数据,最后对这10条数据进行正序排序

# 写法一的固定写法

select * from 表名 where id>=(
  select B.id from (
    select A.id from (
      select id from userinfo where id > 当前页数最后一条数据的id limit 每一页数据的总数 * (需要跳转的页码 - 当前页码)
    ) as A order by A.id desc limit 每一页数据的总数
  ) as B order by B.id asc limit 1
) limit 每一页数据的总数;

# 写法一

select * from userinfo where id>=(
  select B.id from (
    select A.id from (
      select id from userinfo where id > 1000 limit 30
    ) as A order by A.id desc limit 10
  ) as B order by B.id asc limit 1
) limit 10;

# 写法二的固定写法

select * from 表名 where id in (
  select B.id from (
    select A.id from (
      select id from userinfo where id>当前页数最后一条数据的id limit 每一页数据的总数 * (需要跳转的页码 - 当前页码)
    ) as A order by A.id desc limit 每一页数据的总数
  ) as B
) order by id asc;

# 写法二

select * from userinfo where id in (
  select B.id from (
    select A.id from (
      select id from userinfo where id>1000 limit 30
    ) as A order by A.id desc limit 10
  ) as B
) order by id asc;

  • 基于当前的页数往前跳几页的分页优化

    • 上一页 98 99 100 101 102 [103] 下一页

# 计算所要跳转的页数和当前页数相差多少条数据,获取这堆相差的数据,然后进行倒序排序后使用limit获取这堆相差数据的前10条数据(前提是每一页数据为10条),而这前10条数据就是所要跳转页数的数据,最后对这10条数据进行正序排序

# 例如:当前页数是103,然后要获取100页数的数据,前提每一页数据为10条,因为100页数和当前页数相差30数据,所以首先要获取这相差的30条数据,然后再对这30条数据进行倒序排序后使用 limit 获取前10条,而这前10条就是100页数的数据,最后对这10条数据进行正序排序

# 写法一的固定写法

select * from 表名 where id>=(
  select A.id from (
    select id from userinfo where id < 当前页数第一条数据的id order by id desc limit 每一页数据的总数 * (当前页码 - 需要跳转的页码)
  ) as A order by A.id asc limit 1
) limit 每一页数据的总数;

# 写法一

select * from userinfo where id>=(
  select A.id from (
    select id from userinfo where id < 1021 order by id desc limit 30
  ) as A order by A.id asc limit 1
) limit 10;

# 写法二的固定写法

select * from 表名 where id in (
  select B.id from (
    select A.id from (
      select id from userinfo where id < 当前页数第一条数据的id order by id desc limit 每一页数据的总数 * (当前页码 - 需要跳转的页码)
    ) as A order by id asc limit 每一页数据的总数
  ) as B
);

# 写法二

select * from userinfo where id in (
  select B.id from (
    select A.id from (
      select id from userinfo where id<1021 order by id desc limit 30
    ) as A order by id asc limit 10
  ) as B
);